package com.leyou.item.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leyou.common.dto.CartDTO;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.pojo.PageResult;
import com.leyou.item.mapper.SkuMapper;
import com.leyou.item.mapper.SpuDetailMapper;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.mapper.StockMapper;
import com.leyou.order.pojo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * lcd  2020/6/8
 * Description:
 */
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Service
@Slf4j
public class GoodsService {
    @Autowired
    private SpuMapper spuMapper;
    @Autowired
    private SpuDetailMapper spuDetailMapper;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private BrandService brandService;
    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private AmqpTemplate amqpTemplate;

    public PageResult<Spu> queryGoodsByPage(String key, Integer page, Integer rows, Boolean saleable) {
        PageHelper.startPage(page, rows);
        Example example = new Example(Spu.class);
        Example.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(key)) {
            criteria.andLike("title", "%" + key + "%");
        }
        if (saleable != null) {
            criteria.andEqualTo("saleable", saleable);
        }
        //默认排序
        example.setOrderByClause("last_update_time desc");

        List<Spu> spus = spuMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(spus)) {
            throw new LyException(ExceptionEnum.GOOD_NOT_FOUND);
        }
        getBnameAndCnameFromSpuList(spus);
        PageInfo<Spu> pageInfo = new PageInfo<>(spus);
        return new PageResult(pageInfo.getTotal(), spus);
    }

    private void getBnameAndCnameFromSpuList(List<Spu> spus) {
        for (Spu spu : spus) {
            List<Category> categories = categoryService.queryByIds(Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));
            List<String> cnames = categories.stream().map(Category::getName).collect(Collectors.toList());
            String cname = StringUtils.join(cnames, "/");
            spu.setCname(cname);
            String bname = brandService.findById(spu.getBrandId()).getName();
            spu.setBname(bname);
        }
    }

    @Transactional
    public void save(Spu spu) {
        spu.setCreateTime(new Date());
        spu.setLastUpdateTime(spu.getCreateTime());
        spu.setId(null);
        spu.setSaleable(true);
        spu.setValid(false);
        int count = spuMapper.insert(spu);
        if (count != 1) {
            throw new LyException(ExceptionEnum.GOOD_CREATED_FAIL);
        }
        SpuDetail spuDetail = spu.getSpuDetail();
        spuDetail.setSpuId(spu.getId());
        spuDetailMapper.insert(spuDetail);
        List<Sku> skus = spu.getSkus();
        saveStockAndSku(spu, skus);
        //发送mq消息
        try {
            amqpTemplate.convertAndSend("item.insert", spu.getId());
        } catch (Exception e) {
            log.error("新增商品消息发送异常，商品id：{}",  spu.getId(), e);
        }

    }

    public SpuDetail querySpuDetailBySpuId(Long spuId) {
        SpuDetail spuDetail = spuDetailMapper.selectByPrimaryKey(spuId);
        if (spuDetail == null) {
            throw new LyException(ExceptionEnum.GOOD_NOT_FOUND);
        }
        return spuDetail;
    }

    public List<Sku> querySkuBySpuId(Long spuId) {
        Sku sku = new Sku();
        sku.setSpuId(spuId);
        List<Sku> list = skuMapper.select(sku);
        if (CollectionUtils.isEmpty(list)) {
            throw new LyException(ExceptionEnum.GOOD_SKU_NOT_FOUND);
        }
        //查询库存 写法1
//        for (Sku s : list) {
//            Stock stock = stockMapper.selectByPrimaryKey(s.getId());
//            if (stock == null) {
//                throw new LyException(ExceptionEnum.GOOD_STOCK_NOT_FOUND);
//            }
//            s.setStock(stock.getStock());
//        }
        //查询库存 写法2
        return loadStockFromSku(list);
    }

    public void updateGoods(Spu spu) {
        //删除sku和stock
        List<Sku> skus = querySkuBySpuId(spu.getId());
        if(!CollectionUtils.isEmpty(skus)) {
            List<Long> ids = skus.stream().map(Sku::getId).collect(Collectors.toList());
            Example example = new Example(Stock.class);
            example.createCriteria().andIn("skuId", ids);
            stockMapper.deleteByExample(example);
            Sku record = new Sku();
            record.setSpuId(spu.getId());
            this.skuMapper.delete(record);
        }
        //修改spu
        spu.setLastUpdateTime(new Date());
        spu.setSaleable(true);
        spuMapper.updateByPrimaryKeySelective(spu);
        //修改detail
        spuDetailMapper.updateByPrimaryKeySelective(spu.getSpuDetail());
        //新增sku和stock
        int count;
        saveStockAndSku(spu, skus);
        //发送mq消息
        try {
            amqpTemplate.convertAndSend("item.update", spu.getId());
        } catch (Exception e) {
            log.error("修改商品消息发送异常，商品id：{}",  spu.getId(), e);
        }
    }

    private void saveStockAndSku(Spu spu, List<Sku> skus) {
        int count;
        List<Stock> stocks = new ArrayList<>();
        for (Sku sku : skus) {
            sku.setCreateTime(new Date());
            sku.setLastUpdateTime(sku.getCreateTime());
            sku.setSpuId(spu.getId());
            count = skuMapper.insert(sku);//因为下面要用到id ,批量新增没有返回id,所以就不用批量新增
            if (count != 1) {
                throw new LyException(ExceptionEnum.GOOD_CREATED_FAIL);
            }

            Stock stock = new Stock();
            stock.setSkuId(sku.getId());
            stock.setStock(sku.getStock());
            stocks.add(stock);
        }
        count = stockMapper.insertList(stocks);
        if (count != stocks.size()) {
            throw new LyException(ExceptionEnum.GOOD_CREATED_FAIL);
        }
    }

    public Spu querySpuById(Long id) {
        Spu spu = spuMapper.selectByPrimaryKey(id);
        if (spu == null) {
            throw new LyException(ExceptionEnum.GOOD_NOT_FOUND);
        }
        //sku detail一起查询了
        spu.setSkus(querySkuBySpuId(id));
        spu.setSpuDetail(querySpuDetailBySpuId(id));
        return spu;
    }

    public List<Sku> querySkuByIds(List<Long> ids) {
        List<Sku> skuList = skuMapper.selectByIdList(ids);
        if (CollectionUtils.isEmpty(skuList)) {
            throw new LyException(ExceptionEnum.GOOD_NOT_FOUND);
        }
        return loadStockFromSku(skuList);
    }

    private List<Sku> loadStockFromSku(List<Sku> skuList) {
        List<Long> skuIdList = skuList.stream().map(Sku::getId).collect(Collectors.toList());
        List<Stock> stocks = stockMapper.selectByIdList(skuIdList);
        if (CollectionUtils.isEmpty(stocks)) {
            throw new LyException(ExceptionEnum.GOOD_STOCK_NOT_FOUND);
        }
        Map<Long, Integer> stockMap = stocks.stream().collect(Collectors.toMap(Stock::getSkuId, Stock::getStock));
        skuList.forEach(s->s.setStock(stockMap.get(s.getId())));
        return skuList;
    }

    @Transactional
    public void decreaseStock(List<CartDTO> cartDTOS) {
        for (CartDTO cartDTO : cartDTOS) {
            //查询库存,判断是否充足
            //秒杀存在线程安全,如果使用synchronized在分布式情况下没用!!不同jvm没用
            //分布式锁 两种方案 zookeeper或者redis
            //悲观锁 效果锁库,性能差,串行
            //采用乐观锁
            int i = stockMapper.decreaseStock(cartDTO.getSkuId(), cartDTO.getNum());
            if (i != 1) {
                throw new LyException(ExceptionEnum.STOCK_NOT_ENOUGH);
            }

        }
    }
}
